/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   Module Name          : com.yaodian100.core.logger.service.impl.LogServiceImpl
   Module Description   :

   Date Created      : 2009/11/26
   Original Author   : jeff.ma
   Team              : yaodian100
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   MODIFICATION HISTORY
   ------------------------------------------------------------------------------
   Date Modified       Modified by       Comments
   ------------------------------------------------------------------------------
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
package com.yaodian100.core.logger.service.impl;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSON;
import net.sf.json.JSONSerializer;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.admin.utils.AdminHelper;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.logger.service.LogService;

/**
 * @author jeff.ma
 * 
 */
public class LogServiceImpl implements LogService {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	private Map<String, String> sqlMap = new HashMap();
	private Map<String, String> attrsMap = new HashMap();
	private String defaultInsert = "insert into COMM_LOG_COMMON (OID, SERVICE_NAME, SERVICE_METHOD, CREATE_USER, LOG_MESSAGE) values (SEQ_LOG.nextval,?,?,?,?)";
	private String outputFormat = "xml";

	/** default constructor */
	public LogServiceImpl() {
	}

	/**
	 * @param outputFormat the outputFormat to set
	 */
	public void setOutputFormat(String outputFormat) {
		this.outputFormat = outputFormat;
	}

	/**
	 * @param sqlMap the sqlMap to set
	 */
	public void setSqlMap(Map<String, String> sqlMap) {
		this.sqlMap = sqlMap;
	}

	/**
	 * @param attrsMap the attrsMap to set
	 */
	public void setAttrsMap(Map<String, String> attrsMap) {
		this.attrsMap = attrsMap;
	}

	/**
	 * @param sQLINS the sQL_INS to set
	 */
	public void setDefaultInsert(String sQLINS) {
		defaultInsert = sQLINS;
	}

	/**
	 * @param jdbcTemplate the jdbcTemplate to set
	 */
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	/**
	 * @return the jdbcTemplate
	 */
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	/*
	 * (non-Javadoc)
	 * @see com.yaodian100.core.logger.service.LogService#save(java.lang.String, java.lang.String, java.lang.String,
	 * java.lang.String)
	 */

	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void save(String serviceName, String method, Object msg) {
		List objs = new ArrayList();
		try {
			objs.add(serviceName);
			objs.add(method);

			UserDetails user = AdminHelper.getUserDetails();
			if (user != null) {
				objs.add(user.getUsername());
			} else {
				objs.add(null);
			}

			String sql = sqlMap.get(serviceName + "." + method);
			if (StringUtils.isBlank(sql)) {
				sql = sqlMap.get(msg.getClass().getName());
			}

			if ("xml".equals(outputFormat)) {
				objs.add(toXML(msg));
			} else if ("json".equals(outputFormat)) {
				objs.add(toJSON(msg));
			} else {
				objs.add(toXML(msg));
			}

			String attrs = attrsMap.get(serviceName + "." + method);
			if (StringUtils.isBlank(attrs)) {
				attrs = attrsMap.get(msg.getClass().getName());
			}
			if (StringUtils.isNotBlank(attrs)) {
				String[] attrArray = StringUtils.split(attrs, ",");
				for (int i = 0; i < attrArray.length; i++) {
					objs.add(BeanUtils.getProperty(msg, attrArray[i]));
				}
			}

			if (StringUtils.isBlank(sql)) {
				sql = defaultInsert;
			}
			getJdbcTemplate().update(sql, objs.toArray());
		} catch (Throwable e) {
			e.printStackTrace();
			logger.error("log fail, service:{}, method:{}, obj:{}", new Object[] { serviceName, method, msg });
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.yaodian100.core.logger.service.LogService#save(java.lang.String, java.lang.String, java.lang.Object,
	 * java.lang.String)
	 */

	public void save(String serviceName, String method, Object obj, String actorId) {
		List objs = new ArrayList();
		try {
			objs.add(serviceName);
			objs.add(method);

			objs.add(actorId);

			String sql = sqlMap.get(serviceName + "." + method);
			if (StringUtils.isBlank(sql)) {
				sql = sqlMap.get(obj.getClass().getName());
			}
			JSON json = JSONSerializer.toJSON(obj);
			objs.add(json.toString());

			String attrs = attrsMap.get(serviceName + "." + method);
			if (StringUtils.isBlank(attrs)) {
				attrs = attrsMap.get(obj.getClass().getName());
			}
			if (StringUtils.isNotBlank(attrs)) {
				String[] attrArray = StringUtils.split(attrs, ",");
				for (int i = 0; i < attrArray.length; i++) {
					objs.add(BeanUtils.getProperty(obj, attrArray[i]));
				}
			}

			if (StringUtils.isBlank(sql)) {
				sql = defaultInsert;
			}
			getJdbcTemplate().update(sql, objs.toArray());
		} catch (Throwable e) {
			e.printStackTrace();
			logger.error("log fail, service:{}, method:{}, obj:{}", new Object[] { serviceName, method, obj });
		}
	}

	private String toXML(Object entity) throws CoreException {
		String xml = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			BeanWriter beanWriter = new BeanWriter(baos);
			beanWriter.enablePrettyPrint();
			beanWriter.write(entity);
			xml = baos.toString();
			beanWriter.flush();
			baos.flush();
			beanWriter.close();
			baos.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new CoreException("to xml fail", e);
		}
		return xml;
	}

	private String toJSON(Object entity) throws CoreException {
		String json = null;
		try {
			json = JSONSerializer.toJSON(entity).toString();
		} catch (Exception e) {
			e.printStackTrace();
			throw new CoreException("to xml fail", e);
		}
		return json;
	}

}
